home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 November: Tool Chest / Dev.CD Nov 96 TC / Dev.CD Nov 96 TC.toast / Sample Code / Snippets / Sound / SndPlayDoubleBuffer / _source / Private_DBFFFunctions.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-05-06  |  18.3 KB  |  593 lines  |  [TEXT/CWIE]

  1. /*
  2. **    Apple Macintosh Developer Technical Support
  3. **
  4. **    Routines demonstrating how to set up for using SndPlayDoubleBuffer.
  5. **
  6. **    by Mark Cookson, Apple Developer Technical Support
  7. **
  8. **    File:    Private_DBFFFunctions.c
  9. **
  10. **    Copyright ©1996 Apple Computer, Inc.
  11. **    All rights reserved.
  12. **
  13. **    You may incorporate this sample code into your applications without
  14. **    restriction, though the sample code has been provided "AS IS" and the
  15. **    responsibility for its operation is 100% yours.  However, what you are
  16. **    not permitted to do is to redistribute the source as "Apple Sample
  17. **    Code" after having made changes. If you're going to re-distribute the
  18. **    source, we require that you make it clear in the source that the code
  19. **    was descended from Apple Sample Code, but that you've made changes.
  20. */
  21.  
  22. #include "Private_DBFFFunctions.h"
  23.  
  24. /********************************************************************************************
  25.         ** YOU SHOULD NEVER NEED TO CALL ANY OF THE FOLLOWING ROUTINES DIRECTLY **
  26. ********************************************************************************************/
  27.  
  28. /*    Purpose:        This sets all of local and global variables to safe values.
  29.                     This routine is called by ASoundNew, and is    called by the
  30.                     ASoundDone function after it has cleaned up to reset things.
  31.     Side Effects:    None.
  32. */
  33. /*-----------------------------------------------------------------------*/
  34.         OSErr    ASoundInit        (SoundInfoPtr theSoundInfo)
  35. /*-----------------------------------------------------------------------*/
  36. {
  37.     NumVersion    SndManagerVer;
  38.     OSErr        theErr            = noErr;
  39.  
  40.     theSoundInfo->globals.gSupports16Bit    = true;
  41.     theSoundInfo->globals.gSupportsSPDB        = true;
  42.  
  43.     theSoundInfo->signature            = kDBFFSignature;
  44.     theSoundInfo->chan                = kInit;
  45.     theSoundInfo->rateForResume        = kInit;
  46.     theSoundInfo->fileType            = kInit;
  47.     (void)ASoundSetNumBuffers        (theSoundInfo, kInit);
  48.     theSoundInfo->dataStart            = kInit;
  49.     (void)ASoundSetSoundLength        (theSoundInfo, kInit);
  50.     ASoundSetBytesCopied            (theSoundInfo, kInit);
  51.     ASoundSetCurBuffer                (theSoundInfo, kStart);
  52.     (void)ASoundSetBufferSize        (theSoundInfo, kInit);
  53.     theSoundInfo->bytesPerFrame        = kInit;
  54.     theSoundInfo->refNum            = kInit;
  55.     theSoundInfo->vRefNum            = nil;
  56.     theSoundInfo->compFactor        = kNoCompression;
  57.     theSoundInfo->paused            = false;
  58.     theSoundInfo->playing            = false;
  59.     theSoundInfo->adjusting            = false;
  60.     theSoundInfo->soundDone            = false;
  61.     theSoundInfo->backwards            = false;
  62.     theSoundInfo->hasBeenAdjusted    = false;
  63.     theSoundInfo->needsMasking        = false;
  64.  
  65.     /* create a Universal Procedure Pointer (UPP) for our sound callback */
  66.     theSoundInfo->theSoundCallBackUPP = NewSndCallBackProc(ASoundDoneCallBack);
  67.  
  68.     SndManagerVer = SndSoundManagerVersion ();
  69.     theErr = InterrogateSystem (&(theSoundInfo->globals));
  70.     if (theErr == noErr) {
  71.         if (SndManagerVer.majorRev >= kMinSndMgrVer) {
  72.             if ((theSoundInfo->globals.ggestaltSoundAttr & gestaltSndPlayDoubleBuffer) == false) {
  73.                 DebugPrint ("\pSndPlayDoubleBuffer isn't supported!");
  74.                 theSoundInfo->globals.gSupportsSPDB = false;
  75.                 theErr = kNoSPDBErr;
  76.             }
  77.             if ((theSoundInfo->globals.ggestaltSoundAttr & gestalt16BitAudioSupport) == false) {
  78.                 DebugPrint ("\pThis machine doesn't support 16 bit audio!");
  79.                 theSoundInfo->globals.gSupports16Bit = false;
  80.                 theErr = notEnoughHardwareErr;    /* This doesn't have to be a fatal error */
  81.             }
  82.         }
  83.         else {
  84.             theErr = kOldSndMgrErr;
  85.         }
  86.     }
  87.     else {
  88.         theErr = kInitErr;
  89.     }
  90.  
  91.     return theErr;
  92. }
  93.  
  94. /*-----------------------------------------------------------------------*/
  95. Boolean            IsValid                    (SoundInfoPtr theSoundInfo)
  96. /*-----------------------------------------------------------------------*/
  97. {
  98.     return CheckValididity (theSoundInfo, false);
  99. }
  100.  
  101. /*-----------------------------------------------------------------------*/
  102. Boolean            StrictIsValid            (SoundInfoPtr theSoundInfo)
  103. /*-----------------------------------------------------------------------*/
  104. {
  105.     return CheckValididity (theSoundInfo, true);
  106. }
  107.  
  108.  
  109. /*-----------------------------------------------------------------------*/
  110. Boolean            CheckValididity            (SoundInfoPtr theSoundInfo,
  111.                                         Boolean strict)
  112. /*-----------------------------------------------------------------------*/
  113. {
  114.     Boolean        returnValue        = true;        /* Assume success */
  115.  
  116.     if (theSoundInfo == nil) {
  117.         returnValue = false;
  118.     }
  119.     else {
  120.         if (strict == true) {
  121.             if (theSoundInfo->signature != kDBFFSignature) {
  122.                 returnValue = false;
  123.             }
  124.             else {
  125.                 if (theSoundInfo->doubleHeader.dbhNumChannels <= kInit) {
  126.                     returnValue = false;
  127.                 }
  128.                 if (theSoundInfo->doubleHeader.dbhSampleSize <= kInit) {
  129.                     returnValue = false;
  130.                 }
  131.                 if (theSoundInfo->doubleHeader.dbhPacketSize < kInit) {
  132.                     returnValue = false;
  133.                 }
  134.                 if (theSoundInfo->theSoundCallBackUPP == nil) {
  135.                     returnValue = false;
  136.                 }
  137.                 if (theSoundInfo->rateForResume < kInit) {
  138.                     returnValue = false;
  139.                 }
  140.                 if (theSoundInfo->numBuffers <= kInit) {
  141.                     returnValue = false;
  142.                 }
  143.                 if (theSoundInfo->dataStart < kInit) {
  144.                     returnValue = false;
  145.                 }
  146.                 if (theSoundInfo->bytesTotal <= kInit) {
  147.                     returnValue = false;
  148.                 }
  149.                 if (theSoundInfo->bytesCopied <= kInit) {
  150.                     returnValue = false;
  151.                 }
  152.                 if (theSoundInfo->currentBuffer <= kInit) {
  153.                     returnValue = false;
  154.                 }
  155.                 if (theSoundInfo->doubleBufferSize <= kInit) {
  156.                     returnValue = false;
  157.                 }
  158.                 if (theSoundInfo->bytesPerFrame <= kInit) {
  159.                     returnValue = false;
  160.                 }
  161.                 if (theSoundInfo->compFactor <= kInit) {
  162.                     returnValue = false;
  163.                 }
  164.             }
  165.         }
  166.         else {
  167.             if (theSoundInfo->signature != kDBFFSignature) {
  168.                 returnValue = false;
  169.             }
  170.             else {
  171.                 if (theSoundInfo->doubleHeader.dbhNumChannels < kInit) {
  172.                     returnValue = false;
  173.                 }
  174.                 if (theSoundInfo->doubleHeader.dbhSampleSize < kInit) {
  175.                     returnValue = false;
  176.                 }
  177.                 if (theSoundInfo->doubleHeader.dbhPacketSize < kInit) {
  178.                     returnValue = false;
  179.                 }
  180.                 if (theSoundInfo->theSoundCallBackUPP == nil) {
  181.                     returnValue = false;
  182.                 }
  183.                 if (theSoundInfo->rateForResume < kInit) {
  184.                     returnValue = false;
  185.                 }
  186.                 if (theSoundInfo->numBuffers < kInit) {
  187.                     returnValue = false;
  188.                 }
  189.                 if (theSoundInfo->dataStart < kInit) {
  190.                     returnValue = false;
  191.                 }
  192.                 if (theSoundInfo->bytesTotal < kInit) {
  193.                     returnValue = false;
  194.                 }
  195.                 if (theSoundInfo->bytesCopied < kInit) {
  196.                     returnValue = false;
  197.                 }
  198.                 if (theSoundInfo->currentBuffer < kInit) {
  199.                     returnValue = false;
  200.                 }
  201.                 if (theSoundInfo->doubleBufferSize < kInit) {
  202.                     returnValue = false;
  203.                 }
  204.                 if (theSoundInfo->bytesPerFrame < kInit) {
  205.                     returnValue = false;
  206.                 }
  207.                 if (theSoundInfo->compFactor < kInit) {
  208.                     returnValue = false;
  209.                 }
  210.             }
  211.         }
  212.     }
  213.  
  214.     if (returnValue == false) {
  215.         DebugPrint ("\pBad SoundInfoPtr!");
  216.     }
  217.  
  218.     return returnValue;
  219. }
  220.  
  221. /*
  222.     Purpose:        Called by StandardFile for every file in a folder to
  223.                     see if we want to display that file in the open file
  224.                     dialog.  Return false (don't filter) if you want the
  225.                     file displayed, true (do filter) if you don't want
  226.                     it displayed.
  227.  
  228.                     This calls ASoundCanThisPlay() which calls the header
  229.                     parsing routines.  If we can parse the header we
  230.                     should be able to play the file.
  231.     Side Effects:    None.
  232. */
  233. /*-----------------------------------------------------------------------*/
  234. pascal Boolean    ASoundFileFilter        (CInfoPBPtr theFileInfo)
  235. /*-----------------------------------------------------------------------*/
  236. {
  237.     OSErr        theErr            = noErr;
  238.     Boolean        returnValue        = true;        /* by default don't display the file */
  239.  
  240.     theErr = ASoundCanThisPlay (theFileInfo);
  241.     if (theErr == noErr) {                    /* We can play this file. */
  242.         returnValue = false;                /* Display this file */
  243.     }
  244.  
  245.     if (theErr != noErr && theErr != kUnknownFormat) {
  246.         DebugPrint ("\pError in ASoundFileFilter");
  247.     }
  248.  
  249.     return returnValue;
  250. }
  251.  
  252. /*
  253.     Purpose:        Sets how many buffers will be needed to play the entire
  254.                     sound.
  255.     Side Effects:    None.
  256. */
  257. /*-----------------------------------------------------------------------*/
  258.         OSErr    ASoundSetNumBuffers        (SoundInfoPtr theSoundInfo,
  259.                                         long newValue)
  260. /*-----------------------------------------------------------------------*/
  261. {
  262.     OSErr        theErr    = noErr;
  263.  
  264.     if (newValue >= kInit) {
  265.         theSoundInfo->numBuffers = newValue;
  266.     }
  267.     else {
  268.         theErr = kBadValue;
  269.     }
  270.  
  271.     return theErr;
  272. }
  273.  
  274. /*
  275.     Purpose:        To install a callback command into the current sound
  276.                     channel.
  277.     Side Effects:    None.
  278. */
  279. /*-----------------------------------------------------------------------*/
  280.         OSErr    InstallCallBack            (SoundInfoPtr theSoundInfo)
  281. /*-----------------------------------------------------------------------*/
  282. {
  283.     SndCommand    mycmd    = {callBackCmd, kInit, kInit};
  284.     OSErr        theErr    = noErr;
  285.  
  286.     mycmd.param2 = SetCurrentA5();
  287.     theErr = SndDoCommand (theSoundInfo->chan, &mycmd, true);
  288.  
  289.     if (theErr != noErr) {
  290.         DebugPrint ("\pError in InstallCallBack");
  291.     }
  292.  
  293.     return theErr;
  294. }
  295.  
  296. /*
  297.     Purpose:        Gather the information needed (from the sound's header)
  298.                     to setup the structures the Sound Manager will need to
  299.                     play the sound.
  300.     Side Effects:    This will allocate memory for the sound header strucure
  301.                     that will be disposed of by ASoundDonePlaying.
  302. */
  303. /*-----------------------------------------------------------------------*/
  304.         OSErr    SetUpSoundHeader        (SoundInfoPtr theSoundInfo,
  305.                                         unsigned long bufferSize)
  306. /*-----------------------------------------------------------------------*/
  307. {
  308.     long double        sampleRate    = kInit;
  309.     long            dataStart    = kInit,
  310.                     sndLength    = kInit;
  311.     OSErr            theErr        = noErr;
  312.  
  313.     theSoundInfo->chan->userInfo = (long)theSoundInfo;        /* So we know who we are in the SoundCompletion routines */
  314.  
  315.     switch (theSoundInfo->fileType) {
  316.         case kCompressedAIFFFile:
  317.         case kUncompressedAIFFFile:
  318.             theErr = ASoundGetAIFFHeader (theSoundInfo, &dataStart, &sndLength);
  319.             break;
  320.         case kWAVEFile:
  321.             theErr = ASoundGetWAVEHeader (theSoundInfo, &dataStart, &sndLength);
  322.             break;
  323.         case kAUFile:
  324.             theErr = ASoundGetULAWHeader (theSoundInfo, &dataStart, &sndLength);
  325.             break;
  326.         case kSNDResource:
  327.         case kResource:
  328.             theErr = ASoundGetSNDHeader  (theSoundInfo, &dataStart, &sndLength);
  329.             break;
  330.         default:
  331.             theErr = kUnknownFormat;
  332.             break;
  333.     }
  334.  
  335.     theSoundInfo->dataStart = dataStart;
  336.     if (theErr != noErr) {
  337.         DebugPrint ("\pError getting sound's header");
  338.         (void)SndDisposeChannel (theSoundInfo->chan, true);
  339.     }
  340.     else {
  341.         if ((theSoundInfo->doubleHeader.dbhSampleSize == kSixteen) && (theSoundInfo->globals.gSupports16Bit == false)) {
  342.             DebugPrint ("\pThis is a 16 bit sound, this is not a 16 bit capable machine.");
  343.             theErr = notEnoughHardwareErr;
  344.         }
  345.         else {    
  346.             theErr = ASoundSetSoundLength (theSoundInfo, sndLength);
  347.             ASoundSetBytesCopied (theSoundInfo, dataStart);                /* skip the header of the file */
  348.  
  349.             sampleRate = ASoundFixToLongDouble (theSoundInfo->doubleHeader.dbhSampleRate);
  350.  
  351.             if (bufferSize > kInit) {
  352.                 theErr = ASoundSetBufferSize (theSoundInfo, bufferSize);
  353.             }
  354.             else {
  355.                 theErr = ASoundSetBufferSize (theSoundInfo, (((theSoundInfo->doubleHeader.dbhSampleSize / kBitsPerByte) * theSoundInfo->doubleHeader.dbhNumChannels * sampleRate) / kBufLen) / theSoundInfo->compFactor);
  356.             }
  357.  
  358.             if (ASoundGetBufferSize (theSoundInfo) > kInit) {
  359.                 theErr = ASoundSetNumBuffers (theSoundInfo, (ASoundGetNumTotalBytes (theSoundInfo) / ASoundGetBufferSize (theSoundInfo)));
  360.             }
  361.             else {
  362.                 DebugPrint ("\pThe buffer size is zero, this is bad.");
  363.                 theErr = dsZeroDivErr;
  364.             }
  365.  
  366.             theSoundInfo->doubleHeader.dbhDoubleBack = NewSndDoubleBackProc (ASoundDoubleBackProc);
  367.             theSoundInfo->doubleHeader.dbhBufferPtr[kDBBufOne] = nil;
  368.             theSoundInfo->doubleHeader.dbhBufferPtr[kDBBufTwo] = nil;
  369.         }
  370.     }
  371.  
  372.     if (theErr != noErr) {
  373.         DebugPrint ("\pError in SetUpSoundHeader");
  374.     }
  375.  
  376.     return theErr;
  377. }
  378.  
  379. /*
  380.     Purpose:        Pause the playing of the sound.
  381.     Side Effects:    None.
  382. */
  383. /*-----------------------------------------------------------------------*/
  384.         OSErr    PauseSound                (SoundInfoPtr theSoundInfo)
  385. /*-----------------------------------------------------------------------*/
  386. {
  387.     SndCommand        theCmd    = {getRateCmd, kInit, kInit};
  388.     OSErr            theErr    = noErr;
  389.  
  390.     theCmd.param2 = (long)&theSoundInfo->rateForResume;
  391.     theErr = SndDoImmediate (theSoundInfo->chan, &theCmd);
  392.  
  393.     if (theErr == noErr) {
  394.         theCmd.cmd = rateCmd;
  395.         theCmd.param2 = kStopPlaying;
  396.         theErr = SndDoImmediate (theSoundInfo->chan, &theCmd);
  397.         if (theErr == noErr) {
  398.             theSoundInfo->paused = true;
  399.         }
  400.     }
  401.  
  402.     if (theErr != noErr) {
  403.         DebugPrint ("\pError in PauseSound");
  404.     }
  405.  
  406.     return theErr;
  407. }
  408.  
  409. /*
  410.     Purpose:        Resume the playing of the sound.
  411.     Side Effects:    This will reinstall the sound completion callback
  412.                     if it was removed by the ASoundPauseForAdjust function.
  413. */
  414. /*-----------------------------------------------------------------------*/
  415.         OSErr    ResumeSound                (SoundInfoPtr theSoundInfo)
  416. /*-----------------------------------------------------------------------*/
  417. {
  418.     SndCommand        theCmd    = {rateCmd, kInit, kInit};
  419.     OSErr            theErr    = noErr;
  420.  
  421.     theCmd.param2 = theSoundInfo->rateForResume;
  422.     theErr = SndDoImmediate (theSoundInfo->chan, &theCmd);
  423.  
  424.     theErr = SndPlayDoubleBuffer (theSoundInfo->chan, (SndDoubleBufferHeaderPtr)&(theSoundInfo->doubleHeader));
  425.     if (theErr == noErr) {
  426.         theSoundInfo->paused = false;
  427.         if (theSoundInfo->hasBeenAdjusted == true) {
  428.             theErr = InstallCallBack (theSoundInfo);
  429.             theSoundInfo->hasBeenAdjusted = false;
  430.         }
  431.     }
  432.  
  433.     if (theErr != noErr) {
  434.         DebugPrint ("\pError in ResumeSound");
  435.     }
  436.  
  437.     return theErr;
  438. }
  439.  
  440. /*-----------------------------------------------------------------------*/
  441.         OSErr    ASoundSetBufferSize        (SoundInfoPtr theSoundInfo,
  442.                                         long newValue)
  443. /*-----------------------------------------------------------------------*/
  444. {
  445.     OSErr            theErr        = noErr;
  446.  
  447.     if (newValue >= nil) {
  448.         /* Make sure the buffer is an integer multiple of the packet size
  449.            multiplied by the number of channels, otherwise IMA will be
  450.            VERY upset, and WAVE files might not sound too good either. */
  451.         if (theSoundInfo->doubleHeader.dbhPacketSize > kInit) {
  452.             newValue /= (theSoundInfo->doubleHeader.dbhPacketSize * theSoundInfo->doubleHeader.dbhNumChannels);
  453.         }
  454.         newValue *= (theSoundInfo->doubleHeader.dbhPacketSize * theSoundInfo->doubleHeader.dbhNumChannels);
  455.         theSoundInfo->doubleBufferSize = newValue;
  456.     }
  457.     else {
  458.         theSoundInfo->doubleBufferSize = kInit;
  459.         DebugPrint ("\pBad value passed to ASoundSetBufferSize");
  460.         theErr = kBadValue;
  461.     }
  462.  
  463.     if (theErr != noErr) {
  464.         DebugPrint ("\pError in ASoundSetBufferSize");
  465.     }
  466.  
  467.     return theErr;
  468. }
  469.  
  470. /*-----------------------------------------------------------------------*/
  471.         OSErr    ASoundSetSoundLength    (SoundInfoPtr theSoundInfo,
  472.                                         long newValue)
  473. /*-----------------------------------------------------------------------*/
  474. {
  475.     OSErr            theErr        = noErr;
  476.  
  477.     if (newValue >= nil) {
  478.         theSoundInfo->bytesTotal = newValue;
  479.     }
  480.     else {
  481.         theSoundInfo->bytesTotal = kInit;
  482.         theErr = kBadValue;
  483.     }
  484.  
  485.     if (theErr != noErr) {
  486.         DebugPrint ("\pError in ASoundSetSoundLength");
  487.     }
  488.  
  489.     return theErr;
  490. }
  491.  
  492. /*
  493.     Purpose:        The purpose of this routine is to fill out the
  494.                     SndDoubleBufferHeader structure with the information the
  495.                     Sound Manager will need, and to fill out the
  496.                     myParamBlockRec structure with the information the
  497.                     ASoundDoubleBackProc interrupt routine will need.  It
  498.                     then calls ASoundDoubleBackProc to fill the first two
  499.                     buffers.
  500.     Side effects:    This routine allocates two pointers as buffers for the
  501.                     sound that will be playing.
  502.                     This routine allocates two custom paramBlockRecs for
  503.                     the ASoundDoubleBackProc (interrupt routine) to use.
  504. */
  505. /*-----------------------------------------------------------------------*/
  506.         OSErr    ASoundPrimeBuffers        (SoundInfoPtr theSoundInfo)
  507. /*-----------------------------------------------------------------------*/
  508. {
  509.     myParmBlkPtr        myPB            = nil;
  510.     SndDoubleBufferPtr    doubleBuffer    = nil;
  511.     IOCompletionUPP        myIOCompletion    = nil;
  512.     OSErr                theErr            = noErr;
  513.     short                i                = kInit;
  514.  
  515.     for (i = kInit; i <= kOne; ++i) {
  516.         if (theSoundInfo->doubleHeader.dbhBufferPtr[i] == nil) {
  517.             doubleBuffer = (SndDoubleBufferPtr)NewPtrClear (sizeof(SndDoubleBuffer) + ASoundGetBufferSize (theSoundInfo));
  518.             if (doubleBuffer == nil || MemError() != noErr) {
  519.                 DebugPrint("\pNo memory for double buffers!");
  520.                 theErr = memFullErr;
  521.             }
  522.             else {
  523.                 /* Hold the memory in case VM is on, this will help to ensure that we have no sound
  524.                    drop outs caused by the paging of our buffers. */
  525.                 HoldMemory (doubleBuffer, sizeof(SndDoubleBuffer) + ASoundGetBufferSize (theSoundInfo));
  526.                 /* dbNumFrames gets set in the ASoundDoubleBackProc() routine */
  527.                 doubleBuffer->dbFlags = nil;
  528.                 doubleBuffer->dbUserInfo[kSndInfoPtr] = (long)theSoundInfo;        /* Make this point at our SoundInfo struct */
  529.                 myPB = (myParamBlockRec *)NewPtrClear (sizeof(myParamBlockRec));        /* Make one for each buffer so */
  530.                 if (myPB == nil || MemError() != noErr) {                            /* we don't reuse the same paramBlock in */
  531.                     DebugPrint("\pNo memory for a new paramBlockRec!");                /* the ioCompletion routine. */
  532.                     theErr = memFullErr;
  533.                 }
  534.                 else {
  535.                     myPB->myA5 = SetCurrentA5 ();
  536.                     myPB->theSoundInfo = theSoundInfo;
  537.                     myIOCompletion = NewIOCompletionProc (ASoundFileCallBack);
  538.                     myPB->pb.ioParam.ioCompletion = myIOCompletion;
  539.                     myPB->pb.ioParam.ioVRefNum = theSoundInfo->vRefNum;
  540.                     myPB->pb.ioParam.ioRefNum = theSoundInfo->refNum;
  541.                     myPB->pb.ioParam.ioPosMode = fsFromStart + noCacheMask;                /* Set the noCacheBit since we probably won't be reading this again */
  542.                     doubleBuffer->dbUserInfo[kPBPtr] = (long)myPB;
  543.  
  544.                     theSoundInfo->doubleHeader.dbhBufferPtr[i] = doubleBuffer;
  545.                 }
  546.             }
  547.         }
  548.         else {
  549.             doubleBuffer = theSoundInfo->doubleHeader.dbhBufferPtr[i];
  550.         }
  551.  
  552.         ASoundDoubleBackProc (theSoundInfo->chan, doubleBuffer);    /* prime the buffers */
  553.  
  554.     }
  555.  
  556.     if (theErr != noErr) {
  557.         DebugPrint ("\pError in ASoundPrimeBuffers");
  558.         for (i = kInit; i <= kOne; ++i) {
  559.             if (!theSoundInfo->doubleHeader.dbhBufferPtr[i]) {
  560.                 DisposePtr ((Ptr)myIOCompletion);
  561.                 DisposePtr ((Ptr)theSoundInfo->doubleHeader.dbhBufferPtr[i]->dbUserInfo[kSndInfoPtr]);
  562.                 DisposePtr ((Ptr)theSoundInfo->doubleHeader.dbhBufferPtr[i]);
  563.             }
  564.         }
  565.     }
  566.  
  567.     return theErr;
  568. }
  569.  
  570. /* This routine is used to calculate where to put the SFGetFile Dialog */
  571. /*-----------------------------------------------------------------------*/
  572.         Rect    GetMainScreenRect        (void)
  573. /*-----------------------------------------------------------------------*/
  574. {
  575.     GDHandle    mainDevice;
  576.     GrafPtr        mainPort;
  577.     Rect        returnRect;
  578.     long        response;
  579.     
  580.     Gestalt (gestaltQuickdrawVersion, &response);
  581.     
  582.     if (response == gestaltOriginalQD) {
  583.         GetWMgrPort (&mainPort);
  584.         returnRect = mainPort->portRect;
  585.     }
  586.     else {
  587.         mainDevice = GetMainDevice();
  588.         returnRect = (*mainDevice)->gdRect;
  589.     }
  590.  
  591.     return returnRect;
  592. }
  593.